﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Web;
using System.IO;
using System.Text;
using AppEntity;

namespace AppEntity
{
    /// <summary>
    ///AppBuilder 的摘要说明
    /// </summary>
    public static partial class AppBuilderGet
    {
        public static Dictionary<string, Action<HttpContext, string>> Init()
        {
            Dictionary<string, Action<HttpContext, string>> GetDict = new Dictionary<string, Action<HttpContext, string>>();
            GetDict.Add("home", Home);
            GetDict.Add("buildapp", BuildApp);
            GetDict.Add("buildentity", BuildEntity);
            GetDict.Add("buildcategory", BuildCategory);
            GetDict.Add("buildindex", BuildIndex);
            GetDict.Add("buildindexedit", BuildIndexEdit);
            GetDict.Add("getcolsforindex", GetColsForIndex);
            GetDict.Add("removeindex", RemoveIndex);
            GetDict.Add("reindex", ReIndex);
            GetDict.Add("vacuum", Vacuum);
            GetDict.Add("backup", BackUpDB);
            GetDict.Add("memeryused", MemeryUsed);
            GetDict.Add("diskused", DiskUsed);
            return GetDict;
        }

        private static void DiskUsed(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            if (string.IsNullOrEmpty(App)) return;            
            context.Response.Cache.SetMaxAge(TimeSpan.Zero);
            context.Response.Write(new FileInfo(Base.GetDataBaseFilePath(App)).Length.ToString());
        }

        private static void MemeryUsed(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];            
            if (string.IsNullOrEmpty(App)) return;
            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));            
            string Memery = Sqlite.conn.MemoryUsed.ToString();            
            Sqlite.Close();
            context.Response.Cache.SetMaxAge(TimeSpan.Zero);
            context.Response.Write(Memery);
        }

        private static void BackUpDB(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];            
            if (string.IsNullOrEmpty(App)) return;
            if (!File.Exists(Base.GetBackupPath() + "index.xml"))
            {
                File.WriteAllText(Base.GetBackupPath() + "index.xml", "<?xml version='1.0' encoding='utf-8'?><root/>", Encoding.UTF8);
            }

            XElement item = new XElement("item");
                        
            System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
            st.Start();
            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            string BakFile = Base.GetDataBasePath()+ App+"-"+AppEntity.Common.Utility.GetNowTime("yyyyMMddHHmmss")+".sqlite";
            string BakZipFile = Base.GetBackupPath()+ App+"-"+AppEntity.Common.Utility.GetNowTime("yyyyMMddHHmmss")+".zip";
            string BakSettingFile = Base.GetSettingsPath(App);
            System.Data.SQLite.SQLiteConnection Bak = new System.Data.SQLite.SQLiteConnection(@"data source=" + BakFile + ";Version=3;");
            Bak.Open();
            Sqlite.conn.BackupDatabase(Bak, "main", "main", -1, null, 0);
            Bak.Close();
            Sqlite.Close();
            st.Stop();
            long time1 = st.ElapsedMilliseconds;
            item.SetAttribute("dbbaktime", time1.ToString());
            st.Reset();
            st.Start();
            AppEntity.Common.Zip BakZip = new Common.Zip(BakZipFile);
            BakZip.AddFile(BakFile, App+".sqlite");
            BakZip.AddFile(BakSettingFile, "Settings\\appsetting.xml");
            Base.GetAppSetting(App).SelectNodes("/root/app/entities/entity/@name").Each(n => 
            {
                string EntityFile = Base.GetSettingsPath(App,n.Value);
                BakZip.AddFile(EntityFile, "Settings\\"+EntityFile.Substring(EntityFile.LastIndexOf("\\")+1));
            });
            BakZip.Close();
            File.Delete(BakFile);
            st.Stop();
            long time2 = st.ElapsedMilliseconds;
            item.SetAttribute("settingbaktime", time2.ToString());
            item.SetAttribute("totaltime", (time2 + time1).ToString());
            item.SetAttribute("backupfile",BakZipFile);
            item.SetAttribute("app",App);
            item.SetAttribute("datecreated", AppEntity.Common.Utility.GetNowTime());
            item.SetAttribute("filesize", new FileInfo(BakZipFile).Length.ToString());
            XDocument xdom = XDocument.Load(Base.GetBackupPath() + "index.xml");
            xdom.Element("root").Add(item);
            xdom.Save(Base.GetBackupPath() + "index.xml");
            context.Response.Cache.SetMaxAge(TimeSpan.Zero);
            context.Response.Write(item.Attributes().ToDictionary(n=>n.Name.ToString(),n=>n.Value).ToJsArrayString(n=>n.Key, n=>n.Value));
        }        

        private static void Home(HttpContext context, string Action)
        { 
            string Html = AppEntity.Common.Convert.xml2html(Base.GetAppIndex().ToXmlDocument(), Base.GetThemeXslFolder() + "appbuilder\\home.xsl", null);
            context.Response.Write(Html);
        }

        private static void Vacuum(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            string IndexName = context.Request.QueryString["index"];
            if (string.IsNullOrEmpty(App) || string.IsNullOrEmpty(IndexName)) return;
            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            Sqlite.ExecuteSql("VACUUM [{0}]".FormatString(IndexName));
            Sqlite.Close();

            context.Response.Redirect("?app={0}&action=buildindex".FormatString(App));

        }

        private static void ReIndex(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            string IndexName = context.Request.QueryString["index"];
            if (string.IsNullOrEmpty(App) || string.IsNullOrEmpty(IndexName)) return;
            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            Sqlite.ExecuteSql("REINDEX [{0}]".FormatString(IndexName));
            Sqlite.Close();

            context.Response.Redirect("?app={0}&action=buildindex".FormatString(App));

        }

        private static void RemoveIndex(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            string IndexName = context.Request.QueryString["index"];
            if (string.IsNullOrEmpty(App) || string.IsNullOrEmpty(IndexName)) return;

            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            Sqlite.ExecuteSql("DROP INDEX IF EXISTS [{0}]".FormatString(IndexName));
            Sqlite.Close();

            context.Response.Redirect("?app={0}&action=buildindex".FormatString(App));
        }

        private static void GetColsForIndex(HttpContext context, string Action)
        {            
            string App = context.Request.QueryString["app"];
            string Entity = context.Request.QueryString["entity"];
            bool IsCat = context.Request.QueryString["iscat"].ToBoolean();
            string Index = context.Request.QueryString["index"];
            string TableName = "Entity-"+Entity+"-"+(IsCat?"Category":"Data");

            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            string Sql = string.Empty;
            object SqlObj = Sqlite.ExecuteScalar("SELECT sql FROM sqlite_master where type='index' and name='"+Index+"' and tbl_name='" + TableName + "'");
            Sqlite.Close();
            if (SqlObj != null)
            {
                Sql = SqlObj.ToString();
            }
            

            if (!string.IsNullOrEmpty(Sql))
            {
                Sql = Sql.SubstringAfter("[" + TableName + "]");
            }
            StringBuilder sb = new StringBuilder();
            Base.GetEntitySetting(App, Entity).SelectNodes("/root/app/entity/{0}/column", IsCat ? "category" : "columns").Each(n => 
            {
                sb.AppendFormat("<label for='col{0}' title='{3}'><input type='checkbox' {4} name='indexcol' value='{1}' id='col{0}' />{1}<span>({2})</span></label>",
                        n.GetAttribute("colid"),
                        n.GetAttribute("name"),
                        n.GetAttribute("zh-cn"),
                        n.GetAttribute("en-us"),
                        Sql.Contains("["+n.GetAttribute("name")+"]") ? "checked='checked'":""
                    );
            });
            context.Response.Cache.SetMaxAge(TimeSpan.Zero);
            context.Response.Write(sb.ToString());
        }

        private static void BuildIndexEdit(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            string Html = AppEntity.Common.Convert.xml2html(Base.GetAppSetting(App), Base.GetThemeXslFolder() + "appbuilder\\buildindex.xsl", null);
            context.Response.Write(Html);
        }

        private static void BuildIndex(HttpContext context, string Action)
        {
            string App = context.Request.QueryString["app"];
            if (string.IsNullOrEmpty(App)) return;            
            Common.DataBase.Sqlite Sqlite = new Common.DataBase.Sqlite(Base.GetDataBaseFilePath(App));
            string XmlStr = Sqlite.SelectData2Xml("SELECT rowid, name, tbl_name, sql FROM [sqlite_master] WHERE type='index' order by rowid desc");
            Sqlite.Close();
            XDocument xdom = XDocument.Load(new StringReader(XmlStr));
            xdom.Element("root").Elements("item").Each(n=>
            {
                string Sql = n.GetAttribute("sql");
                string TableName = n.GetAttribute("tbl_name");
                string Cols = Sql.SubstringAfter("[" + TableName + "]");
                Cols = Cols.ReplaceRegExp(@"[\(\[\]\);\s]","").Replace(",",", ");
                n.SetAttribute("sql", Cols);
            });
            Hashtable Param = new Hashtable();
            Param.Add("appindex", Base.GetAppIndex().ToXmlDocument());
            string Html = AppEntity.Common.Convert.xml2html(xdom.ToXmlDocument(), Base.GetThemeXslFolder() + "appbuilder\\buildindex.xsl", Param);
            context.Response.Write(Html);
        }

        private static void BuildCategory(HttpContext context, string Action)
        { 
            string App = context.Request.QueryString["app"];
            string Entity = context.Request.QueryString["entity"];
            XDocument xdom = XDocument.Load(Base.GetSettingsPath(App, Entity));
            xdom.SelectNodes("/root/app/entity/columns/column").Remove();
            xdom.SelectSingleNode("/root/app/entity/columns").Add(xdom.SelectNodes("/root/app/entity/category/column"));
            XmlDocument dom = xdom.ToXmlDocument();

            XmlDocument Setting = new XmlDocument();
            Setting.Load(Base.GetSettingsPath() + "AppBuilderSetting.xml");
            Hashtable Param = new Hashtable();
            Param.Add("appdom", Base.GetAppSetting(App));
            Param.Add("setting", Setting);
            Param.Add("maxcolid", dom.SelectNodes("/root/app/entity/columns/column/@colid").ToList(n => n.Value.ToInt32(0)).Max());
            Param.Add("type", "cat");
            string Html = AppEntity.Common.Convert.xml2html(dom, Base.GetThemeXslFolder() + "appbuilder\\buildentity.xsl", Param);
            context.Response.Write(Html);
        }

        private static void BuildApp(HttpContext context, string Action)
        {
            string app = context.Request.QueryString["app"];
            XmlDocument dom = new XmlDocument();
            if (string.IsNullOrEmpty(app))
            {
                dom.LoadXml("<root/>");
            }
            else
            {
                dom.Load(Base.GetSettingsPath(app));
            }

            string Html = AppEntity.Common.Convert.xml2html(dom, Base.GetThemeXslFolder() + "appbuilder\\buildapp.xsl", null);
            context.Response.Write(Html);
        }

        private static void BuildEntity(HttpContext context, string Action)
        {
            string app = context.Request.QueryString["app"];
            string entity = context.Request.QueryString["entity"];
            XmlDocument dom = new XmlDocument();
            bool NewEntity = false;
            if (string.IsNullOrEmpty(entity))
            {
                dom.LoadXml("<root/>");
                NewEntity = true;
            }
            else
            {
                dom.Load(Base.GetSettingsPath(app, entity));
            }
            XmlDocument Setting = new XmlDocument();
            Setting.Load(Base.GetSettingsPath() + "AppBuilderSetting.xml");
            Hashtable Param = new Hashtable();
            Param.Add("appdom", Base.GetAppSetting(app));
            Param.Add("setting", Setting);
            Param.Add("maxcolid", NewEntity==true ? 1000 : dom.SelectNodes("/root/app/entity/columns/column/@colid").ToList(n=>n.Value.ToInt32(0)).Max());
            Param.Add("type", "entity");
            string Html = AppEntity.Common.Convert.xml2html(dom, Base.GetThemeXslFolder() + "appbuilder\\buildentity.xsl", Param);
            context.Response.Write(Html);
        }
    }
}